﻿#Region "*********************************************************** Imports "
Imports System
Imports System.ComponentModel
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
#End Region

#Region "*********************************************************** History"
'********************************************************************************
'* The purpose of this class is to allow readonly combo boxes to display black
'* when in readonly mode
'* This control will display in the tool box in screen design mode that is why 
'********************************************************************************
'+------------+-------+----------+-----------------------------------------------------------+
'| DATE       | NAME  | TPR      | DESCRIPTION                                               |
'+------------+-------+----------+-----------------------------------------------------------+
'| 19/01/2010 | ISDYN | 00055013 |Public Class SoS_ComboBox_Ext                              |
'+------------+-------+----------+-----------------------------------------------------------+    
'| 17/03/2010 | ISDYN | 00057697 |Font color change; residual issues                         |
'+------------+-------+----------+-----------------------------------------------------------+
'| 30/03/2010 | ISdyn | 00058317 | Added Data_Rules_Engine abd standard binding              |
'+------------+-------+----------+-----------------------------------------------------------+
'| 13/04/2010 | ISJXZ | 00058490 |blank fields in member cover screen                        |
'+------------+-------+----------+-----------------------------------------------------------+
#End Region

''' <summary>
''' Represents a Windows combo box control. It enhances the .NET standard combo box control
''' with a ReadOnly mode.
''' </summary>
<ComVisible(False)> _
Public Class SoS_ComboBox_Ext
    Inherits System.Windows.Forms.ComboBox

#Region "*********************************************************** Member variables"
    ' The embedded TextBox control that is used for the ReadOnly mode
    Public Event ValidateThisCombo(ByVal sender As Object, ByVal e As System.EventArgs)
    Private WithEvents _textbox_Value As TextBox
    Private _textbox_Display As TextBox

    ' true, when the ComboBox is set to ReadOnly
    Private _isReadOnly As Boolean

    ' true, when the control is visible
    Private _visible As Boolean = True

    Private WithEvents _Timer As Timer

    Private _Debug As Boolean = False

    Private _SelectError As Boolean = False

    Private _SelectedIndex As Integer = False

    Private _err As ErrorProvider

#End Region

#Region "*********************************************************** Constructor"
    ''' <summary>
    ''' Default Constructor
    ''' </summary>
    Public Sub New()
        _textbox_Value = New TextBox()
        _textbox_Display = New TextBox()
        _err = New ErrorProvider
        _Timer = New Timer
    End Sub
#End Region

#Region "*********************************************************** Public Properties "
    ''' <summary>
    ''' Shows Value and display value above and below the comob box
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Debug() As Boolean
        Get
            Return _Debug
        End Get
        Set(ByVal value As Boolean)
            _Debug = value
        End Set
    End Property

    ''' <summary>
    ''' Get value for error status
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property SelectError() As Boolean
        Get
            Return _SelectError
        End Get
        Set(ByVal value As Boolean)
            _SelectError = value
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets a value indicating whether the control is read-only.
    ''' </summary>
    ''' <value>
    ''' <b>true</b> if the combo box is read-only; otherwise, <b>false</b>. The default is <b>false</b>.
    ''' </value>
    ''' <remarks>
    ''' When this property is set to <b>true</b>, the contents of the control cannot be changed 
    ''' by the user at runtime. With this property set to <b>true</b>, you can still set the value
    ''' in code. You can use this feature instead of disabling the control with the Enabled
    ''' property to allow the contents to be copied.        
    ''' </remarks>        
    <Browsable(True)> _
    <DefaultValue(False)> _
    <Category("Behavior")> _
    <Description("Controls whether the value in the combobox control can be changed or not")> _
    Public Property [ReadOnly]() As Boolean
        '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        ' Known issue with the custom control  (TPR 00055013)
        ' donot set SoS_Combo_Ext to readonly in design time if you are going to 
        ' bind a datatable to the control. 
        ' Set readonly mode in code only 
        '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        Get
            Return _isReadOnly
        End Get
        Set(ByVal value As Boolean)
            If value <> _isReadOnly Then
                _isReadOnly = value
                ShowControl()
            End If
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets a value indicating wether the control is displayed.
    ''' </summary>
    ''' <value><b>true</b> if the control is displayed; otherwise, <b>false</b>. 
    ''' The default is <b>true</b>.</value>
    Public Shadows Property Visible() As Boolean
        Get
            Return _visible
        End Get
        Set(ByVal value As Boolean)
            _visible = value
            ShowControl()
        End Set
    End Property

    ''' <summary>
    ''' Conceals the control from the user.
    ''' </summary>
    ''' <remarks>
    ''' Hiding the control is equvalent to setting the <see cref="Visible"/> property to <b>false</b>. 
    ''' After the <b>Hide</b> method is called, the <b>Visible</b> property returns a value of 
    ''' <b>false</b> until the <see cref="Show"/> method is called.
    ''' </remarks>
    Public Shadows Sub Hide()
        Visible = False
    End Sub

    ''' <summary>
    ''' Gets or sets selected value
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shadows Property SelectedValue() As String
        Get
            Return _textbox_Value.Text
        End Get
        Set(ByVal value As String)
            If value <> _textbox_Value.Text Then
                _textbox_Value.Text = value
                'FindMyValue(value)
                OnSelectedValueChanged(Nothing)
            End If

        End Set
    End Property

    ''' <summary>
    ''' Gets or sets Selected Text
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shadows Property SelectedText() As String
        Get
            ' _textbox_Value.DataBindings(0).GetType()
            Return _textbox_Display.Text
        End Get
        Set(ByVal value As String)
            _textbox_Display.Text = value
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets Selected index
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shadows Property SelectedIndex() As Integer
        Get
            Return _SelectedIndex
        End Get
        Set(ByVal value As Integer)
            If _SelectedIndex <> value Then
                MyBase.SelectedIndex = _SelectedIndex
                _SelectedIndex = value
                'MyBase.OnSelectedIndexChanged(Nothing)
            End If
        End Set
    End Property

    ''' <summary>
    ''' Displays the control to the user.
    ''' </summary>
    ''' <remarks>
    ''' Showing the control is equivalent to setting the <see cref="Visible"/> property to <b>true</b>.
    ''' After the <b>Show</b> method is called, the <b>Visible</b> property returns a value of 
    ''' <b>true</b> until the <see cref="Hide"/> method is called.
    ''' </remarks>
    Public Shadows Sub Show()
        Visible = True
    End Sub

    ''' <summary>
    ''' Apply custom data binding
    ''' </summary>
    ''' <param name="pComboDataTable"></param>
    ''' <param name="pComboDisplayMember"></param>
    ''' <param name="pComboValueMember"></param>
    ''' <param name="pDataTable"></param>
    ''' <param name="PColumnName"></param>
    ''' <param name="pAddBlank"></param>
    ''' <remarks></remarks>
    Public Sub SOS_DataBindings(ByRef pComboDataTable As DataTable, _
                         ByVal pComboDisplayMember As String, _
                         ByVal pComboValueMember As String, _
                         ByRef pDataTable As Object, ByVal PColumnName As String, _
                         Optional ByVal pAddBlank As Boolean = False)

        _textbox_Value.DataBindings.Clear()
        Try
            If pAddBlank Then
                Dim strOrigFiller As String = pComboDataTable.DefaultView.RowFilter
                Dim dv As DataView = pComboDataTable.DefaultView
                dv.RowFilter = pComboValueMember & "= ''"
                If dv.Count = 0 Then
                    dv.RowFilter = ""
                    Dim dr As DataRow = pComboDataTable.NewRow
                    dr(pComboDisplayMember) = ""
                    dr(pComboValueMember) = ""
                    pComboDataTable.Rows.Add(dr)
                End If
                dv.RowFilter = strOrigFiller
            End If
        Catch ex As Exception

        End Try

        MyBase.DataBindings.Clear()

        MyBase.DataSource = pComboDataTable
        MyBase.DisplayMember = pComboDisplayMember
        MyBase.ValueMember = pComboValueMember

        _textbox_Value.DataBindings.Add(New Binding("Text", pDataTable, PColumnName))
        Me.DataBindings.Add(New Binding("SelectedValue", pDataTable, PColumnName, Nothing, DataSourceUpdateMode.Never))

        CheckDebug()
    End Sub

    ''' <summary>
    ''' Apply / reapply dataset filter to combobox
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub ApplyFilter()
        ActionValueChange()
        _Timer.Enabled = True
    End Sub

#End Region
   
#Region "*********************************************************** Private methods"
    ''' <summary>
    ''' Initializes the embedded TextBox with the default values from the ComboBox
    ''' </summary>
    Private Sub AddTextbox()
        _textbox_Value.[ReadOnly] = True
        _textbox_Display.ReadOnly = True
        _textbox_Value.Location = Me.Location
        _textbox_Display.Location = Me.Location
        _textbox_Value.Size = Me.Size
        _textbox_Display.Size = Me.Size
        _textbox_Value.Dock = Me.Dock
        _textbox_Display.Dock = Me.Dock
        _textbox_Value.Anchor = Me.Anchor
        _textbox_Display.Anchor = Me.Anchor
        _textbox_Value.Enabled = MyBase.Enabled
        _textbox_Display.Enabled = MyBase.Enabled
        _textbox_Value.Visible = Me.Visible
        _textbox_Display.Visible = Me.Visible
        _textbox_Value.RightToLeft = Me.RightToLeft
        _textbox_Display.RightToLeft = Me.RightToLeft
        _textbox_Value.Font = Me.Font
        _textbox_Display.Font = Me.Font
        _textbox_Display.Visible = True
        _textbox_Value.BringToFront()
        _textbox_Display.BringToFront()
        _textbox_Display.ReadOnly = True

        _textbox_Value.TabStop = False
        _textbox_Display.TabStop = MyBase.TabStop
        Me.TabStop = False

        _textbox_Value.TabIndex = Me.TabIndex
        _textbox_Display.TabIndex = Me.TabIndex


        _Timer.Interval = 100
        _Timer.Enabled = True

    End Sub

    ''' <summary>
    ''' Shows either the ComboBox or the TextBox or nothing, depending on the state
    ''' of the ReadOnly, Enable and Visible flags.
    ''' </summary>
    Private Sub ShowControl()
        If _isReadOnly Then
            MyBase.Visible = True
            _textbox_Value.Visible = _visible AndAlso Me.Enabled
            'MyBase.Visible = _visible AndAlso Not Me.Enabled
            MyBase.Enabled = Not _isReadOnly
            'MyBase.SendToBack()
            _textbox_Display.BringToFront()
            _textbox_Display.BackColor = SystemColors.Control
        Else
            _textbox_Display.BackColor = SystemColors.Window
            _textbox_Display.BringToFront()
            _textbox_Value.Visible = False
            'MyBase.Visible = _visible
            MyBase.Enabled = Not _isReadOnly
        End If
        ActionValueChange()
        _Timer.Enabled = True
        CheckDebug()
    End Sub

    Private Function FindMyValue(ByVal value As String) As Integer
        Dim iIndex As Integer = -1
        Dim bErr As Boolean = False
        Try
            For Each dr As DataRowView In MyBase.Items
                iIndex += 1
                If value = dr(MyBase.ValueMember).ToString Then
                    Try
                        _SelectedIndex = iIndex
                        'If _textbox_Value.Text <> dr(MyBase.ValueMember).ToString Then
                        _textbox_Value.Text = dr(MyBase.ValueMember).ToString
                        _textbox_Display.Text = dr(MyBase.DisplayMember).ToString
                        'End If                        
                        bErr = False
                        MyBase.SelectedIndex = iIndex
                        Exit For
                    Catch ex As Exception
        End Try
                Else
                    bErr = True
                End If
            Next
        Catch ex As Exception

        End Try

        If bErr Then
            If Me.Enabled Then
                _err.SetError(Me, MyBase.ValueMember & " invalid " & value)
            End If
            _SelectedIndex = -1
            _textbox_Display.Text = value
            SelectError = True
        Else
            _err.SetError(Me, "")
            SelectError = False
        End If
        Return _SelectedIndex
    End Function

    Private Sub ActionValueChange()
        If Not _Timer.Enabled Then
            FindMyValue(_textbox_Value.Text)
            _textbox_Display.SelectionStart = 0
            _textbox_Display.SelectionLength = 0
            _textbox_Display.BringToFront()
            RaiseEvent ValidateThisCombo(Me, Nothing)
            'OnSelectedIndexChanged(Nothing)
        Else
            _Timer.Enabled = True
        End If
        CheckDebug()
    End Sub

    Private Sub _textbox_Value_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles _textbox_Value.TextChanged
        ActionValueChange()
        _Timer.Enabled = True
    End Sub

    Private Sub CheckDebug()
        If _Debug Then
            _textbox_Display.BringToFront()
            _textbox_Value.BringToFront()
            _textbox_Value.Visible = True
            _textbox_Display.Visible = True

            _textbox_Value.Top = MyBase.Top - 20
            _textbox_Display.Top = MyBase.Top + 20

            _textbox_Display.BorderStyle = BorderStyle.FixedSingle
            _textbox_Value.BorderStyle = BorderStyle.FixedSingle
        End If
    End Sub

#End Region

#Region "*********************************************************** OnXXXX()"
    
    ''' <summary>
    ''' This member overrides <see cref="Control.OnParentChanged"/>
    ''' </summary>
    ''' <param name="e"></param>
    Protected Overloads Overrides Sub OnParentChanged(ByVal e As EventArgs)
        MyBase.OnParentChanged(e)

        If Parent IsNot Nothing Then
            AddTextbox()
        End If
        _textbox_Value.Parent = Me.Parent
        _textbox_Display.Parent = Me.Parent
    End Sub

    
    ''' <summary>
    ''' This member overrides see cref="ReadOnlyComboBox.OnSelectedIndexChanged"/>.
    ''' </summary>
    Protected Overrides Sub OnSelectedIndexChanged(ByVal e As EventArgs)
        Try
            Dim dr As DataRowView
            '_SelectedIndex = MyBase.SelectedIndex
            If _SelectedIndex >= 0 Then
                dr = MyBase.Items(MyBase.SelectedIndex)
                'If _textbox_Value.Text <> dr(MyBase.ValueMember).ToString Then
                _textbox_Value.Text = dr(MyBase.ValueMember).ToString
                _textbox_Display.Text = dr(MyBase.DisplayMember).ToString
                'End If
            Else
            End If
            FindMyValue(_textbox_Value.Text)
            MyBase.OnSelectedIndexChanged(e)

        Catch ex As Exception

        End Try
    End Sub

    ''' <summary>
    ''' This member overrides see cref="ReadOnlyComboBox.OnDropDownStyleChanged"/>.
    ''' </summary>
    Protected Overloads Overrides Sub OnDropDownStyleChanged(ByVal e As EventArgs)
        MyBase.OnDropDownStyleChanged(e)
    End Sub

    ''' <summary>
    ''' This member overrides see cref="ReadOnlyComboBox.OnFontChanged"/>.
    ''' </summary>
    ''' <param name="e"></param>
    Protected Overloads Overrides Sub OnFontChanged(ByVal e As EventArgs)
        MyBase.OnFontChanged(e)
        _textbox_Value.Font = Me.Font
        _textbox_Display.Font = Me.Font
    End Sub

    ''' <summary>
    ''' This member overrides see cref="ReadOnlyComboBox.OnResize"/>.
    ''' </summary>
    ''' <param name="e"></param>
    Protected Overloads Overrides Sub OnResize(ByVal e As EventArgs)
        MyBase.OnResize(e)
        _textbox_Value.Size = Me.Size
        _textbox_Value.Width = Me.Width - 19

        _textbox_Display.Size = Me.Size
        _textbox_Display.Width = Me.Width - 19
        _textbox_Display.Height = Me.Height + 2

        CheckDebug()
    End Sub

    ''' <summary>
    ''' This member overrides <see cref="Control.OnDockChanged"/>.
    ''' </summary>
    ''' <param name="e"></param>
    Protected Overloads Overrides Sub OnDockChanged(ByVal e As EventArgs)
        MyBase.OnDockChanged(e)
        _textbox_Value.Dock = Me.Dock
        _textbox_Display.Dock = Me.Dock
    End Sub

    ''' <summary>
    ''' This member overrides <see cref="Control.OnEnabledChanged"/>.
    ''' </summary>
    ''' <param name="e"></param>
    Protected Overloads Overrides Sub OnEnabledChanged(ByVal e As EventArgs)
        MyBase.OnEnabledChanged(e)
        ShowControl()
    End Sub

    ''' <summary>
    ''' This member overrides <see cref="Control.OnRightToLeftChanged"/>.
    ''' </summary>
    ''' <param name="e"></param>
    Protected Overloads Overrides Sub OnRightToLeftChanged(ByVal e As EventArgs)
        MyBase.OnRightToLeftChanged(e)
        _textbox_Value.RightToLeft = Me.RightToLeft
        _textbox_Display.RightToLeft = Me.RightToLeft
    End Sub

    ''' <summary>
    ''' This member overrides <see cref="Control.OnTextChanged"/>.
    ''' </summary>
    ''' <param name="e"></param>    
    Protected Overloads Overrides Sub OnTextChanged(ByVal e As EventArgs)
        MyBase.OnTextChanged(e)
    End Sub

    ''' <summary>
    ''' This member overrides <see cref="Control.OnLocationChanged"/>.
    ''' </summary>
    ''' <param name="e"></param>
    Protected Overloads Overrides Sub OnLocationChanged(ByVal e As EventArgs)
        MyBase.OnLocationChanged(e)
        _textbox_Value.Location = Me.Location
        _textbox_Display.Location = Me.Location
    End Sub

    ''' <summary>
    ''' This member overrides <see cref="Control.OnTabIndexChanged"/>.
    ''' </summary>
    ''' <param name="e"></param>
    Protected Overloads Overrides Sub OnTabIndexChanged(ByVal e As EventArgs)
        MyBase.OnTabIndexChanged(e)
        _textbox_Value.TabIndex = Me.TabIndex
        _textbox_Display.TabIndex = Me.TabIndex
    End Sub

    ''' This allows the dataset / dataview to init
    Private Sub _Timer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles _Timer.Tick
        _Timer.Enabled = False
        ActionValueChange()

    End Sub


#End Region

End Class